package main

import (
	"01/functional/fib"
	"bufio"
	"fmt"
	"os"
)

func tryDefer() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	fmt.Println(3)
	return // panic("error")   这都不影响，输出结果依然为 3 2 1
	fmt.Println(4)
}

func writeFile(filename string) {
	file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) // 0666 linux 文件权限,  加了这个os.O_EXCL，文件存在会打开不了。 人为制造一个错误异常
	if err != nil {
		// panic(err) 这里不能单纯的进行 panic， 中断程序。可以进行细致的错误处理

		// 1. 进行打印输出， 再返回。不让异常中断程序
		// fmt.Println("file already exists ", err)
		// return 

		// 2. 打开OpenFile()函数源码会发现， If there is an error, it will be of type *PathError, err 是接口类型，实现Error()方法，这里报错将返回的是 *PathError
		if pathError, ok := err.(*os.PathError); !ok {  // 类型断言，看是否会报这个类型的错
			panic(err)  // 当送进来的不是 *os.PathError 类型，直接 panic
		} else {
			fmt.Println(pathError.Op,  // 输出一些 关于pathError的信息
			pathError.Path,
			pathError.Err)
		}
		return
	}

	defer file.Close() // 完成时关闭文件
	// 直接写文件比较慢， 利用bufio
	writer := bufio.NewWriter(file)   // buffer 缓冲，先写入到内存中去，到一定大小时，一次性写入硬盘中
	defer writer.Flush() // 只写入buffer 缓冲，还需要导进去
 
	f := fib.Fibonacci()
	for i := 0; i < 20; i++ {
		fmt.Fprintln(writer, f())
	}

}

func forDefer() {
	for i := 0; i < 100; i++ {
		defer fmt.Print(i, " ")
		if i == 30 {
			panic("error")
		}
	}
}

func main() {
	tryDefer()
	writeFile("fib.txt")
	forDefer()
}